#pragma once

#include "compiler.hpp"
#include "runner.hpp"
#include "../comm/log.hpp"
#include "../comm/util.hpp"

#include <signal.h>
#include <jsoncpp/json/json.h>
#include <unistd.h>

namespace ns_complie_run
{
    using namespace ns_compiler;
    using namespace ns_runner;
    using namespace ns_log;
    using namespace ns_util;

    class ComplieRun
    {
    public:
        ComplieRun() = default;
        ~ComplieRun() = default;

        // 清除临时文件
        static void RemoveTempFile(const std::string& file_name)
        {
            std::string filein = PathUtil::Stdin(file_name);
            if(FileUtil::isFileExist(filein))
                unlink(filein.c_str());

            std::string fileout = PathUtil::Stdout(file_name);
            if(FileUtil::isFileExist(fileout))
                unlink(fileout.c_str());

            std::string fileerr = PathUtil::Stderr(file_name);
            if(FileUtil::isFileExist(fileerr))
                unlink(fileerr.c_str());

            std::string complie_error = PathUtil::CompileError(file_name);
            if(FileUtil::isFileExist(complie_error))
                unlink(complie_error.c_str());

            std::string exe = PathUtil::Exe(file_name);
            if(FileUtil::isFileExist(exe))
                unlink(exe.c_str());

            std::string src = PathUtil::Src(file_name);
            if(FileUtil::isFileExist(src))
                unlink(src.c_str());
        }   
        // 状态码转换为描述
        static std::string StatusToDesc(int status, const std::string& file_name)
        {
            std::string desc;
            switch(status)
            {
            case 0:
                desc = "程序正常编译运行";
                break;
            case SIGABRT: // 6
                desc = "内存超出限定范围";
                break;
            case SIGXCPU: // 24
                desc = "CPU使用时间超出";
                break;
            case SIGFPE: // 8
                desc = "浮点数异常溢出";
                break;
            case SIGSEGV: // 11
                desc = "出现段错误";
                break;
            case -1:
                desc = "提交代码为空";
                break;
            case -2:
                desc = "未知错误"; // 后端问题，不能展示给用户
                break;
            case -3:
                // desc = "编译出错";
                FileUtil::ReadFile(PathUtil::CompileError(file_name), &desc, true);
                break;
            case -4:
                desc = "未知错误"; // 运行内部出错，同样用未知错误表示
                break;
            default:
                desc = std::to_string(status) + " 未知错误";
                break;
            }
            return desc;
        }
        
        /*****************************************
         * Start 函数 -- 收到客户端发送的json字符串，处理该字符串，编译运行程序，并返回结果字符串，且要完成错误处理
         * 参数：in_json -- 客户端发送的json字符串，包含 code，input，cpu_limit，mem_limit等
         * out_json -- 输出型参数，返回编译运行结果，包含 status, reason, stdout, stderr等
         *      status -- >0，运行时出现异常 ； =0，正常运行；<0，有其他错误
        *****************************************/
        static void Start(const std::string& in_json, std::string* out_json)
        {
            // 从输入中提取参数
            Json::Value inval;
            Json::Reader reader;
            reader.parse(in_json, inval);
            std::string code = inval["code"].asString();
            std::string input = inval["input"].asString();
            int cpu_limit = inval["cpu_limit"].asInt();
            int mem_limit = inval["mem_limit"].asInt();

            int status = 0; // 默认运行成功
            std::string uniquename;
            int run_ret;

            if(code.size() == 0)
            {
                // LOG(WARING) << "code输入为空" << std::endl;
                status = -1; // code输入为空
                goto END;
            }

            // 获取唯一名称
            uniquename = FileUtil::GetUniqeName();

            // 生成源文件
            if(!FileUtil::WriteFile(code, PathUtil::Src(uniquename)))
            {
                status = -2; // 写入源文件失败
                goto END;
            }

            // 编译
            if(!Compiler::Compile(uniquename))
            {
                status = -3; // 编译出错
                goto END;
            }

            // 保存运行时的状态码
            // 运行
            run_ret = Runner::Run(uniquename, cpu_limit, mem_limit);
            if(run_ret > 0) // 运行异常
            {
                status = run_ret;
            }
            else if(run_ret < 0)
            {
                status = -4; // 运行错误
            }

            END:
            // 序列化返回字符串
            Json::Value outval;
            Json::StyledWriter writer;
            outval["status"] = status;
            outval["reason"] = StatusToDesc(status, uniquename);
            // 当编译运行完全没有问题时，才可能有输出数据和输出错误
            if(status == 0)
            {
                std::string out;
                FileUtil::ReadFile(PathUtil::Stdout(uniquename), &out, true);
                outval["stdout"] = out;

                std::string err;
                FileUtil::ReadFile(PathUtil::Stderr(uniquename), &err, true);
                outval["stderr"] = err;
            }
            *out_json = writer.write(outval);

            RemoveTempFile(uniquename);
        }
    };
}